﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	WebFormsService.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Workflow;
using Smart.Common.Entities;

namespace Smart.Common.Forms
{
	/// <summary>
	/// SharePoint forms service
	/// </summary>
	public abstract class WebFormsService : FormsService
	{
		protected override void LoadServiceValuesToCtx()
		{
			base.LoadServiceValuesToCtx();

			var site = SPH.GetCurrentSite();
			var web = SPH.GetCurrentWeb();
			var list = SPH.GetCurrentList();
			var item = SPH.GetCurrentItem();

			Ctx.Values["SiteUrl"] = site != null ? site.ServerRelativeUrl.TrimEnd('/') : string.Empty;
			Ctx.Values["SiteFullUrl"] = site != null ? site.Url.TrimEnd('/') : string.Empty;

			Ctx.Values["WebUrl"] = web != null ? web.ServerRelativeUrl.TrimEnd('/') : string.Empty;
			Ctx.Values["WebFullUrl"] = web != null ? web.Url.TrimEnd('/') : string.Empty;

			if (list != null)
			{
				Ctx.Values["ListID"] = list.ID.ToString();
				Ctx.Values["ListUrl"] = list.GetServerRelativeUrl().TrimEnd('/');
			}
			else
			{
				Ctx.Values["ListID"] = string.Empty;
				Ctx.Values["ListUrl"] = string.Empty;
			}

			var page = WebExts.GetPage();

			if (page != null)
			{
				Ctx.Values["PageUrl"] = page.Request.Url.AbsolutePath;
				Ctx.Values["RootFolder"] = page.Request["RootFolder"];
			}
			else
			{
				Ctx.Values["PageUrl"] = string.Empty;
				Ctx.Values["RootFolder"] = string.Empty;
			}

			if ((item != null) && (Ctx.Mode != MetaFormMode.New))
			{
				Ctx.Values["ItemID"] = item.ID.ToString();
				Ctx.Values["ItemUrl"] = item.Url.TrimEnd('/');

				SPFolder rootFolder = null;

				switch (item.FileSystemObjectType)
				{
					case SPFileSystemObjectType.File:
						if (item.File != null)
							rootFolder = item.File.ParentFolder;
						break;

					case SPFileSystemObjectType.Folder:
						if (item.Folder != null)
							rootFolder = item.Folder.ParentFolder;
						break;

					default:
						rootFolder = item.Folder;
						break;
				}

				if (rootFolder != null)
					Ctx.Values["RootFolder"] = rootFolder.GetServerRelativeUrl();
			}
			else
			{
				Ctx.Values["ItemID"] = string.Empty;
				Ctx.Values["ItemUrl"] = string.Empty;
			}
		}

		public override bool PerformAction(string actionName, string[] actionArgs, out bool handled)
		{
			switch (actionName.ToLower())
			{
				case "setfieldvalue":
					handled = true;
					return SetFieldValue(actionArgs[0], actionArgs[1]);
				case "setfieldrequired":
					handled = true;
					return SetFieldRequired(actionArgs[0], actionArgs[1].SToBool(false));
			}

			return base.PerformAction(actionName, actionArgs, out handled);
		}

		public virtual FormField GetFormField(string fieldName)
		{
			var mf = Ctx.Form.FindByName(fieldName);
			var cf = mf != null ? mf.Control as CompositeField : null;

			return
				cf != null
					? cf.FindControlRecursive<FormField>()
					: null;
		}

		public virtual bool SetFieldValue(string fieldName, string fieldValue)
		{
			var ff = GetFormField(fieldName);

			if (ff != null)
			{
				if (fieldValue.IsNullOrEmpty())
				{
					ff.Value = null;
					return true;
				}

				switch (fieldValue.ToLower())
				{
					case "[currentuserid]":
						ff.Value = SPH.GetCurrentUser().FormatLookupValue();
						return true;
				}

				ff.Value = fieldValue;
				return true;
			}
			else
			{
				var webEntity = Ctx.Entity.Source as WebEntity;

				if (webEntity == null)
					return false;

				var item = webEntity.GetItem();

				if (fieldValue.IsNullOrEmpty())
				{
					item.Set(fieldName, null);

					return true;
				}

				switch (fieldValue.ToLower())
				{
					case "[currentuserid]":
						item.Set(fieldName, SPH.GetCurrentUser().ID);
						return true;
				}

				item.Set(fieldName, fieldValue);
				return true;
			}
		}

		public virtual bool SetFieldRequired(string fieldName, bool required)
		{
			var ff = GetFormField(fieldName);

			if (ff == null)
				return false;

			ff.Field.Required = required;

			return true;
		}

		public override bool ExecuteFunction(string functionName, string[] functionArgs, out bool handled)
		{
			switch (functionName.ToLower())
			{
				case "isuserinfield":
					handled = true;
					return IsUserInField(functionArgs[0]);

				case "isuseringroup":
					handled = true;
					return IsUserInGroup(functionArgs[0]);

				case "fielddle":
					handled = true;
					return FieldDLe(functionArgs[0], functionArgs[1]);

				case "fielddlt":
					handled = true;
					return FieldDLt(functionArgs[0], functionArgs[1]);

				case "fielddge":
					handled = true;
					return FieldDGe(functionArgs[0], functionArgs[1]);

				case "fielddgt":
					handled = true;
					return FieldDGt(functionArgs[0], functionArgs[1]);

				case "oncreate":
				case "isnew":
					handled = true;
					return IsNew();

				case "isnotsenttoapprove":
				case "notsendtoapprove":
					handled = true;
					return IsNotSentToApprove();

				case "isinitiator":
					handled = true;
					return IsInitiator();

				case "isauthor":
					handled = true;
					return IsAuthor();

				case "isapprovers":
					handled = true;
					return IsApprovers();

				case "issignator":
					handled = true;
					return IsSignator();

				case "isnotsignator":
					handled = true;
					return !IsSignator();

				case "userhastasks":
					handled = true;
					return UserHasTasks();

				case "istasktitle":
					handled = true;
					return IsTaskTitle(functionArgs[0]);

				case "isnottasktitle":
					handled = true;
					return !IsTaskTitle(functionArgs[0]);

				case "istasktitlecontains":
					handled = true;
					return IsTaskTitleContains(functionArgs[0]);

				case "isnottasktitlecontains":
					handled = true;
					return !IsTaskTitleContains(functionArgs[0]);

				case "isWorkflowrunning":
					handled = true;
					return IsWorkflowRunning(functionArgs[0]);

				case "iscontenttype":
					handled = true;
					return IsContentType(functionArgs[0]);

				case "isnotcontenttype":
					handled = true;
					return !IsContentType(functionArgs[0]);

				case "isnotpostback":
					handled = true;
					return IsNotPostBack();

				case "isdocsattached":
					handled = true;
					return IsDocsAttached();

				case "isnotdocsattached":
					handled = true;
					return IsNotDocsAttached();
			}

			return base.ExecuteFunction(functionName, functionArgs, out handled);
		}

		public virtual bool IsUserInField(string fieldName)
		{
			return
				Ctx.Values[fieldName + ".ID"]
					.SToStr(string.Empty)
					.Split(new[] { SPH.MultiLookupValueDelimiter }, StringSplitOptions.RemoveEmptyEntries)
					.Select(s => s.SToInt(0))
					.Where(i => i > 0)
					.Any(SPH.IsCurrentUserOrHisGroup);
		}

		public virtual bool IsUserInGroup(string groupName)
		{
			return
				SPH.IsCurrentUserInGroup(groupName);
		}

		public virtual bool FieldDLe(string fieldName, string value)
		{
			return
				Ctx.Values[fieldName].SToDbl(0) <= value.SToDbl(0);
		}

		public virtual bool FieldDLt(string fieldName, string value)
		{
			return
				Ctx.Values[fieldName].SToDbl(0) < value.SToDbl(0);
		}

		public virtual bool FieldDGt(string fieldName, string value)
		{
			return
				Ctx.Values[fieldName].SToDbl(0) > value.SToDbl(0);
		}

		public virtual bool FieldDGe(string fieldName, string value)
		{
			return
				Ctx.Values[fieldName].SToDbl(0) >= value.SToDbl(0);
		}

		public virtual bool IsNew()
		{
			return Ctx.Mode == MetaFormMode.New;
		}

		public virtual bool IsInitiator()
		{
			var principalId = Ctx.Values.SafeGetInt("RIInitiator.ID", 0);

			return SPH.IsCurrentUserOrHisGroup(principalId);
		}

		public virtual bool IsAuthor()
		{
			var principalId = Ctx.Values.SafeGetInt(SN.AuthorField + ".ID", 0);

			return SPH.IsCurrentUserOrHisGroup(principalId);
		}

		public virtual bool IsApprovers()
		{
			var principalIds = (Ctx.Values.SafeGetStr("RIApproversUser.ID", null) ?? string.Empty).Split(true, SPH.MultiLookupValueDelimiter).Select(s => s.SToInt()).Where(i => i > 0);

			return principalIds.Any(SPH.IsCurrentUserOrHisGroup);
		}

		public virtual bool IsSignator()
		{
			var principalId = Ctx.Values.SafeGetInt("RISignatoryUser.ID", 0);

			return SPH.IsCurrentUserOrHisGroup(principalId);
		}

		public virtual bool IsNotSentToApprove()
		{
			return Ctx.Values.SafeGet("RIApprovalStatusLP") == null;
		}

		public virtual bool UserHasTasks()
		{
			var webEntity = Ctx.Entity.Source as WebEntity;

			if (webEntity == null)
				return false;

			var task = webEntity.GetItem().Tasks.FindMyTask();

			return
				task != null;
		}

		public virtual bool IsTaskTitle(string title)
		{
			var webEntity = Ctx.Entity.Source as WebEntity;

			if (webEntity == null)
				return false;

			var task = webEntity.GetItem().Tasks.FindMyTask();

			return
				task != null && task.Title.EqIC(title);
		}

		public virtual bool IsTaskTitleContains(string title)
		{
			var webEntity = Ctx.Entity.Source as WebEntity;

			if (webEntity == null)
				return false;

			var task = webEntity.GetItem().Tasks.FindMyTask();

			return
				task != null && task.Title.IndexOf(title, StringComparison.OrdinalIgnoreCase) >= 0;
		}

		public virtual bool IsWorkflowRunning(string WorkflowId)
		{
			var entity = Ctx.Entity.Source as WebEntity;

			if (entity == null)
				return false;

			var item = entity.GetItem();

			if (WorkflowId.IsNullOrEmpty())
				return item.Workflows.OfType<SPWorkflow>().Any(Workflow => Workflow.IsInRunningState());

			if (WorkflowId.IsGuid())
			{
				var guid = WorkflowId.SToGuid(Guid.Empty);

				return
					item.Workflows.OfType<SPWorkflow>()
						.Any(Workflow => Workflow.IsInRunningState() && Workflow.ParentAssociation.BaseId == guid);
			}

			return
				item.Workflows.OfType<SPWorkflow>()
					.Any(Workflow => Workflow.IsInRunningState() && Workflow.ParentAssociation.Name.EqIC(WorkflowId));
		}

		public virtual bool IsContentType(string contentTypeId)
		{
			if (!contentTypeId.IsContentTypeId())
				return false;

			var ctid = new SPContentTypeId(contentTypeId);
			var ectid = new SPContentTypeId(Ctx.Entity.ContentTypeId);

			return
				ectid == ctid || ectid.IsChildOf(ctid);
		}

		public virtual bool IsDocsAttached()
		{
			var entity = Ctx.Entity.Source as WebEntity;

			if (entity == null)
				return false;

			var item = entity.GetItem();

			if (item == null)
				return false;

			switch (item.FileSystemObjectType)
			{
				case SPFileSystemObjectType.Web:
					return true;

				case SPFileSystemObjectType.File:
					return true;

				case SPFileSystemObjectType.Folder:
					return item.Folder.ItemCount > 0;

				case SPFileSystemObjectType.Invalid:
					return item.Attachments.Count > 0;
			}

			return false;
		}

		public virtual bool IsNotDocsAttached()
		{
			var entity = Ctx.Entity.Source as WebEntity;

			if (entity == null)
				return true;

			var item = entity.GetItem();

			if (item == null)
				return true;

			switch (item.FileSystemObjectType)
			{
				case SPFileSystemObjectType.Web:
					return false;

				case SPFileSystemObjectType.File:
					return false;

				case SPFileSystemObjectType.Folder:
					return item.Folder.ItemCount <= 0;

				case SPFileSystemObjectType.Invalid:
					return item.Attachments.Count <= 0;
			}

			return true;
		}

		public virtual bool IsNotPostBack()
		{
			var page = WebExts.GetPage();

			return
				page != null && !page.IsPostBack;
		}
	}
}